﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NthDownload.Common.ViewModels;
using System.Windows;
using System.ComponentModel.Composition;
using NthDownload.Contracts;
using System.IO;
using HtmlAgilityPack;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Threading;

namespace NthDownload.DownloadPlugins.Http.ViewModels
{
    public class HttpDownloadsAddViewModel: ViewModelScreenBase
    {
        #region Class Members

        private string _path;
        private string _destinationPath;
        private int _loadDepth;
        private int _loadCount;
        private ObservableCollection<HttpNode> _rootNodes;

        #endregion Class Members

        #region Constructors

        public HttpDownloadsAddViewModel()
        {
            TryGetPathFromClipboard();
            DestinationPath = Settings.DefaultDestinationPath;
            RootNodes = new ObservableCollection<HttpNode>();
        }

        #endregion Constructors

        #region Properties

        /// <summary>
        /// Source of the download
        /// </summary>
        public string Path 
        {
            get
            {
                return _path;
            }
            set
            {
                _path = value;
                NotifyOfPropertyChange(() => Path);
            }
        }

        /// <summary>
        /// Destination of the download
        /// </summary>
        public string DestinationPath
        {
            get
            {
                return _destinationPath;
            }
            set
            {
                _destinationPath = value;
                NotifyOfPropertyChange(() => DestinationPath);
            }
        }

        /// <summary>
        /// The nodes for the current path
        /// </summary>
        public ObservableCollection<HttpNode> RootNodes
        {
            get
            {
                return _rootNodes;
            }
            private set
            {
                _rootNodes = value;
                NotifyOfPropertyChange(() => RootNodes);
            }
        }

        /// <summary>
        /// Current Settings
        /// </summary>
        [Import(AllowRecomposition = true)]
        public HttpSettings Settings { get; set; }

        /// <summary>
        /// The Synchronization Context of the executing thread
        /// </summary>
        [Import(typeof(SynchronizationContext), AllowRecomposition = true)]
        public SynchronizationContext UISynchronizationContext { get; set; }

        #endregion Properties

        #region Methods

        /// <summary>
        /// Closes the dialog with a save result
        /// </summary>
        public void Ok()
        {
            if (!BindingGroupValidator.ValidateBindingExpressionsWithUpdate())
            {
                return;
            }

            Result = ViewModelResults.Ok;
            TryClose();
        }

        /// <summary>
        /// Closes the dialog with a save result
        /// </summary>
        public void Cancel()
        {
            Result = ViewModelResults.Cancel;
            TryClose();
        }

        /// <summary>
        /// Changes the destination path
        /// </summary>
        public void ChangeDestination()
        {
            System.Windows.Forms.FolderBrowserDialog dlgDest = new System.Windows.Forms.FolderBrowserDialog();
            if (dlgDest.ShowDialog() != System.Windows.Forms.DialogResult.OK)
            {
                return;
            }

            DirectoryInfo diDest = new DirectoryInfo(dlgDest.SelectedPath);

            if (!diDest.Exists)
            {
                return;
            }

            DestinationPath = diDest.FullName;
        }

        /// <summary>
        /// Refreshes the list of links using the current path
        /// </summary>
        public void RefreshFromSource()
        {
            RefreshFromSource(true);
        }

        /// <summary>
        /// Refreshes the list of links using the current path
        /// </summary>
        public void RefreshFromSource(bool validate)
        {
            RootNodes.Clear();

            Uri testUri;
            if (validate && BindingGroupValidator.ValidateBindingExpressionsWithUpdate())
            {
                RootNodes.Add(new HttpNode(Path));
            }
            else if (Uri.TryCreate(Path, UriKind.Absolute, out testUri))
            {
                RootNodes.Add(new HttpNode(Path));
            }
        }

        /// <summary>
        /// Loads the given nodes children
        /// </summary>
        public void LoadChildren(HttpNode httpNode)
        {
            if (httpNode == null || !BindingGroupValidator.ValidateBindingExpressionsWithUpdate()) return;

            httpNode.LoadChildren(true);
        }

        /// <summary>
        /// Cancels the children load the given node
        /// </summary>
        public void CancelLoadChildren(HttpNode httpNode)
        {
            if (httpNode == null) return;

            httpNode.CancelLoadChildren();
        }

        /// <summary>
        /// Cancels the children load for the given node recisrively
        /// </summary>
        public void CancelLoadChildrenRecursively(HttpNode httpNode)
        {
            if (httpNode == null) return;

            httpNode.CancelLoadChildren();

            foreach (HttpNode childHttpNode in httpNode.Children)
            {
                CancelLoadChildrenRecursively(childHttpNode);
            }
        }
        
        /// <summary>
        /// Sets the children of a node to be selected
        /// </summary>
        public void SelectChildren(HttpNode httpNode)
        {
            if (httpNode == null) return;
            httpNode.IsExpanded = true;

            foreach (HttpNode node in httpNode.Children)
            {
                node.IsSelected = true;
            }
        }

        /// <summary>
        /// Recursively sets the children of a node to be selected
        /// </summary>
        public void SelectChildrenRecursively(HttpNode httpNode)
        {
            if (httpNode == null) return;
            httpNode.IsExpanded = true;

            foreach (HttpNode node in httpNode.Children)
            {
                node.IsSelected = true;
                SelectChildrenRecursively(node);
            }
        }

        /// <summary>
        /// Sets the children of a node to be deselected
        /// </summary>
        public void DeselectChildren(HttpNode httpNode)
        {
            if (httpNode == null) return;
            httpNode.IsExpanded = false;

            foreach (HttpNode node in httpNode.Children)
            {
                node.IsSelected = false;
            }
        }

        /// <summary>
        /// Recursively sets the children of a node to be deselected
        /// </summary>
        public void DeselectChildrenRecursively(HttpNode httpNode)
        {
            if (httpNode == null) return;
            httpNode.IsExpanded = false;

            foreach (HttpNode node in httpNode.Children)
            {
                node.IsSelected = false;
                DeselectChildrenRecursively(node);
            }
        }

        /// <summary>
        /// Used to handle key down events
        /// </summary>
        public void KeyDown(KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                RefreshFromSource(true);
            }
        }

        /// <summary>
        /// Used to handle when the UI has loaded
        /// </summary>
        public void UILoaded()
        {
            RefreshFromSource(false);
        }

        /// <summary>
        /// Used to handle when the UI has loaded
        /// </summary>
        public void UIUnloaded()
        {
            foreach (HttpNode httpNode in RootNodes)
            {
                CancelLoadChildrenRecursively(httpNode);   
            }
        }

        #endregion Methods

        #region Private Methods

        /// <summary>
        /// Tries to get a path from the current text in the clipboard
        /// </summary>
        private void TryGetPathFromClipboard()
        {
            Uri uri;
            if (!Uri.TryCreate(Clipboard.GetText(), UriKind.Absolute, out uri)) return;
            if (uri.Scheme != "http" && uri.Scheme != "https") return;

            Path = uri.OriginalString;
        }

        #endregion Private Methods
    }
}
